<?php

namespace ApiSdk\SmallRedBook\Servers\Auth;


use ApiSdk\SmallRedBook\Servers\Request\SmallRedBookBaseRequest;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Redis\RedisManager;

/**
 * 小红书授权类
 * @package App\Servers\SmallRedBook\Auth
 */
class SmallRedBookAuth extends SmallRedBookBaseRequest
{


    /**
     * 授权获取code
     * author: Linqh
     * Date  2021/11/20 14:16
     * @param int $state 标识位，返回时将原值返回，可用于标识商家
     * @return string
     */
    public function getAuthCode($state = 0)
    {
        $this->addParam('appId', $this->appId);
        $this->addParam('redirectUri', $this->redirectUri);
        $this->addParam('state', $state);
        return $this->authUrl . '/ark/authorization?' . http_build_query($this->param);
    }

    /**
     * 根据code获取访问令牌
     * author: Linqh
     * Date  2021/11/20 14:03
     * @return mixed
     */
    public function getAccessToken($code)
    {
        $this->setCommonParam('oauth.getAccessToken');
        $this->addParam('code', $code);
        return $this->post();
    }

    /**
     * 刷新访问令牌
     * author: Linqh
     * Date  2021/11/20 14:07
     * @param $refreshToken //刷新令牌
     * @return mixed
     */
    public function refreshToken($refreshToken)
    {
        $this->addParam('method', 'oauth.refreshToken');
        $this->setCommonParam('oauth.refreshToken');
        $this->addParam('refreshToken', $refreshToken);
        return $this->post();
    }

    private function getRedisManager()
    {
        return app(RedisManager::class);
    }

    private function getAccessTokenKey(string $shopId): string
    {
        return "platform_auth:SmallRedBook:access_token:${shopId}";
    }


    private function getRefreshTokenKey($shopId): string
    {
        return "platform_auth:SmallRedBook:refresh_token:${shopId}";
    }


    /**
     * Notes: 设置缓存
     * author: lfy
     * Date: 2021/11/19
     * Time: 17:20
     * @param $TokenData
     * @return bool
     */
    public function setAccessTokenCache($tokenData)
    {
        $redisManager = $this->getRedisManager();
        try {
            $accessToken        = $tokenData['accessToken'];
            $refreshToken       = $tokenData['refreshToken'];
            $token_expires_at   = floor($tokenData['accessTokenExpiresAt'] / 1000);
            $refresh_expires_at = floor($tokenData['refreshTokenExpiresAt'] / 1000);

            $expiresIn          = floor($token_expires_at - time());
            $refreshExpiresIn   = floor($refresh_expires_at - time());
            $shopId             = $tokenData['sellerId'];
            $minRefreshLeftTime = 1800;//  30 minutes before the token expires
            $userId             = $tokenData['user_id'] ?? 0;
            $id                 = $tokenData['id'] ?? 0;
            $shopName           = $tokenData['shop_name'] ?? $shopId;
            $isCb               = $tokenData['is_cb'] ?? 0;
            $isGlobal           = $tokenData['is_global'] ?? 0;
            $expiresIn          -= $minRefreshLeftTime;
            $refreshExpiresIn   -= $minRefreshLeftTime;

            $redisManager->pipeline(function ($pipe) use ($tokenData,$shopId, $accessToken, $expiresIn, $refreshExpiresIn, $refreshToken, $userId, $id, $shopName,$isCb,$isGlobal) {
                $accessTokenKey = $this->getAccessTokenKey($id);
                $cacheData      = array_merge($tokenData,[
                    'access_token' => $accessToken,
                    'shop_id'      => $shopId,
                    'user_id'      => $userId,
                    'id'           => $id,
                    'shop_name'    => $shopName,
                    'is_cb'        => $isCb,
                    'is_global'    => $isGlobal
                ]);
                $pipe->set($accessTokenKey, json_encode($cacheData));
                $pipe->expire($accessTokenKey, $expiresIn);

                $refreshTokenKey = $this->getRefreshTokenKey($id);
                unset($cacheData['access_token']);
                $cacheData['refresh_token'] = $refreshToken;

                $pipe->set($refreshTokenKey, json_encode($cacheData));
                $pipe->expire($refreshTokenKey, $refreshExpiresIn);

            });
            return true;
        } catch (\Exception $e) {

            \Log::error('设置快手 AccessToken到缓存异常', ['msg' => $e->getMessage(), 'token_data' => []]);
            return false;
        }
    }

    /**
     * Notes: 从缓存中获取 AccessToken
     * author: lfy
     * Date: 2021/11/10
     * Time: 16:30
     * @param string $shopId
     * @param string $func
     * @return mixed|string
     */
    public function getAccessTokenBySellerId($shopId, $func = '')
    {
        $redisManager   = $this->getRedisManager();
        $accessTokenKey = $this->getAccessTokenKey($shopId);
        $accessToken    = $redisManager->get($accessTokenKey);
        // AccessToken 过期
        if (empty($accessToken)) {
            $refreshTokenKey = $this->getRefreshTokenKey($shopId);
            $refreshToken    = $redisManager->get($refreshTokenKey);
            // RefreshToken 过期
            $tokenData = [];
            if (!empty($refreshToken)) {
                $tokenData              = $this->refreshToken($refreshToken['refresh_token']);
                $accessToken            = [
                    'access_token' => $tokenData['accessToken'] ?? '',
                    'shop_id'      => $refreshToken['shop_id'],
                    'user_id'      => $refreshToken['user_id'],
                    'id'           => $refreshToken['id'],
                    'shop_name'    => $refreshToken['shop_name'],
                    'is_global'    => $refreshToken['is_global'] ?? 0,
                    'is_cb'        => $refreshToken['is_cb'] ?? 0,
                ];
                $tokenData['user_id']   = $refreshToken['user_id'];
                $tokenData['id']        = $refreshToken['id'];
                $tokenData['shop_name'] = $refreshToken['shop_name'];
                $tokenData['is_global'] = $accessToken['is_global'];
                $tokenData['is_cb']     = $accessToken['is_cb'];
                $this->setAccessTokenCache($tokenData);

            }
            if (is_callable($func)) $func($tokenData);
        }
        return $accessToken;
    }

    public function getRedisKey($shopId = '*')
    {
        $redisManager   = $this->_getRedisManager();
        $accessTokenKey = $this->_getAccessTokenKey($shopId);
        return $redisManager->keys($accessTokenKey);
    }
}
